package cn.texous.web.parsing.book.manager;

import cn.texous.util.commons.util.CollectionUtils;
import cn.texous.util.commons.util.GsonUtils;
import cn.texous.util.commons.util.Md5Util;
import cn.texous.util.commons.util.StringUtils;
import cn.texous.web.parsing.book.common.constants.RedisKey;
import cn.texous.web.parsing.book.common.utils.RedisClient;
import cn.texous.web.parsing.book.config.ServerConfig;
import cn.texous.web.parsing.book.model.entity.mysql.AnaBook;
import cn.texous.web.parsing.book.model.entity.mysql.AnaBookChapter;
import cn.texous.web.parsing.book.model.entity.mysql.AnaUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 缓存管理器
 *
 * @author Showa.L
 * @since 2020/3/12 9:57
 */
@Slf4j
@Component
public class RedisManager {

    @Autowired
    private ServerConfig sc;
    private static ServerConfig serverConfig;

    @PostConstruct
    private void init() {
        serverConfig = sc;
    }

    /**
     * 存储书籍信息
     *
     * @param book 书籍信息
     */
    public static void cacheBookInfo(AnaBook book) {
        if (serverConfig.getOpenCache()) {
            // 根据 origin, name, author 存储
            try {
                String keyMd5 = getBookCodeKey(book.getAnaOriginCode(), book.getName(), book.getAuthor());
                RedisClient.set(getKey(RedisKey.BOOK_CODE_KEY_PREFIX, keyMd5), book.getCode());
                // 根据 code 存储 book
                RedisClient.set(getKey(RedisKey.BOOK_INFO_KEY_PREFIX, book.getCode()), GsonUtils.toJson(book));
            } catch (Exception e) {
                log.error("【缓存书籍信息失败】: {}", e.getMessage());
            }
        }
    }

    /**
     * 批量缓存书籍信息
     *
     * @param anaBooks 书籍列表
     */
    public static void cacheBookInfo(List<AnaBook> anaBooks) {
        anaBooks.forEach(RedisManager::cacheBookInfo);
    }

    /**
     * 获取书籍信息
     *
     * @param origin 来源
     * @param name   书籍名称
     * @param author 书籍作者
     * @return
     */
    public static AnaBook getBookInfo(String origin, String name, String author) {
        if (serverConfig.getOpenCache()) {
            String keyMd5 = getBookCodeKey(origin, name, author);
            String bookCode = RedisClient.get(getKey(RedisKey.BOOK_CODE_KEY_PREFIX, keyMd5));
            if (!StringUtils.isTrimEmpty(bookCode)) {
                return getBookInfo(bookCode);
            }
        }
        return null;
    }

    /**
     * 获取书籍信息
     *
     * @param bookCode 书籍 code
     * @return
     */
    public static AnaBook getBookInfo(String bookCode) {
        if (serverConfig.getOpenCache()) {
            String bookInfoStr = RedisClient.get(getKey(RedisKey.BOOK_INFO_KEY_PREFIX, bookCode));
            return GsonUtils.fromJson(bookInfoStr, AnaBook.class);
        }
        return null;
    }

    /**
     * 判断是否存在书籍缓存
     *
     * @param bookCode 书籍code
     * @return
     */
    public static boolean existsBookInfo(String bookCode) {
        if (serverConfig.getOpenCache()) {
            return RedisClient.exists(getKey(RedisKey.BOOK_INFO_KEY_PREFIX, bookCode));
        }
        return false;
    }

    /**
     * 缓存章节信息
     *
     * @param chapter 章节信息
     */
    public static void cacheBookChapterInfo(AnaBookChapter chapter) {
        if (serverConfig.getOpenCache()) {
            try {
                RedisClient.hset(getKey(RedisKey.CHAPTERS_INFO_KEY_PREFIX, chapter.getAnaBookCode()),
                        chapter.getCode(), GsonUtils.toJson(chapter));
            } catch (Exception e) {
                log.error("【缓存章节信息失败】: {}", e.getMessage());
            }
        }
    }

    /**
     * 缓存目录
     *
     * @param chapters 目录
     * @param bookCode 书籍code
     */
    public static void cacheBookChapterInfo(Map<String, String> chapters, String bookCode) {
        if (serverConfig.getOpenCache()) {
            try {
                RedisClient.hmset(getKey(RedisKey.CHAPTERS_INFO_KEY_PREFIX, bookCode), chapters);
            } catch (Exception e) {
                log.error("【缓存章节信息失败】: {}", e.getMessage());
            }
        }
    }

    /**
     * 批量缓存章节信息
     *
     * @param anaBookChapters 章节列表
     */
    public static void cacheBookChapterInfo(List<AnaBookChapter> anaBookChapters) {
        if (serverConfig.getOpenCache()) {
            anaBookChapters.forEach(RedisManager::cacheBookChapterInfo);
        }
    }

    /**
     * 获取章节信息
     *
     * @param bookChapterCode 章节 code
     * @param bookCode        书籍 code
     * @return
     */
    public static AnaBookChapter getBookChapterInfo(String bookChapterCode, String bookCode) {
        if (serverConfig.getOpenCache()) {
            String chapterInfoStr = RedisClient.hget(
                    getKey(RedisKey.CHAPTERS_INFO_KEY_PREFIX, bookCode), bookChapterCode);
            return GsonUtils.fromJson(chapterInfoStr, AnaBookChapter.class);
        }
        return null;
    }

    public static AnaBookChapter getFirstChapter(String bookCode) {
        if (serverConfig.getOpenCache()) {
            return Optional.ofNullable(bookCode)
                    .map(RedisManager::getBookChapterInfos)
                    .map(cs -> cs.stream()
                            .sorted(Comparator.comparing(AnaBookChapter::getNumber))
                            .findFirst()
                            .orElse(null))
                    .orElse(null);
        }
        return null;
    }

    /**
     * 获取章节列表
     *
     * @param bookCode
     * @return
     */
    public static List<AnaBookChapter> getBookChapterInfos(String bookCode) {
        if (serverConfig.getOpenCache()) {
            Map<String, String> chapterInfos = RedisClient.hgetAll(getKey(RedisKey.CHAPTERS_INFO_KEY_PREFIX, bookCode));
            return Optional.ofNullable(chapterInfos)
                    .filter(CollectionUtils::isNotEmpty)
                    .map(Map::values)
                    .map(vs -> vs.stream()
                            .map(s -> GsonUtils.fromJson(s, AnaBookChapter.class))
                            .collect(Collectors.toList())).orElse(null);
        }
        return null;
    }

    /**
     * 判断是否已经缓存了书籍章节信息
     *
     * @param bookCode 书籍 code
     * @return
     */
    public static boolean existsChapters(String bookCode) {
        if (serverConfig.getOpenCache()) {
            Long lenth = RedisClient.hlen(getKey(RedisKey.CHAPTERS_INFO_KEY_PREFIX, bookCode));
            return lenth != null && lenth > 0;
        }
        return false;
    }

    public static String userLogin(AnaUser anaUser) {
        if (serverConfig.getOpenCache()) {
            String token = StringUtils.randomCharacter(32);
            RedisClient.setex(getKey(RedisKey.LOGIN_USER_INFO_KEY_PREFIX, token),
                    24 * 60 * 60, GsonUtils.toJson(anaUser));
            return token;
        }
        return null;
    }

    /**
     * 生成书籍 code 缓存 key
     *
     * @param origin 来源
     * @param name   名称
     * @param author 作者
     * @return
     */
    public static String getBookCodeKey(String origin, String name, String author) {
        String key = new StringBuilder()
                .append(origin)
                .append("-")
                .append(name)
                .append("-")
                .append(author)
                .toString();
        return Md5Util.md5Hex(key);
    }

    /**
     * 拼接生成 redis key
     *
     * @param redisKeyPrefix redis key 前缀
     * @param after          redis key 标识
     * @return
     */
    private static String getKey(RedisKey redisKeyPrefix, String after) {
        return redisKeyPrefix.getPrefix() + after;
    }

    public static void main(String[] args) {
        String s = "alsdkjflaksdjf-再见了我的青春啊来自一-头北方的狼有没有啊啊搭街坊拉萨的解放拉萨打发士大夫sdfasdfasdfasdfasdfasdfasdf";
        String str = Md5Util.md5(s);
        System.out.println(str);
        System.out.println(Md5Util.md5Hex(s));
    }

}
